package com.tonyodev.fetch2core;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.agp.utils.TextTool;
import ohos.app.Context;
import ohos.data.rdb.ValuesBucket;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.net.Uri;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * 存储解析器辅助
 *
 * @since 2021-05-20
 */
public class StorageResolverHelper {
    private static DataAbilityHelper helper;

    /**
     * 单例
     *
     * @param context 上下文
     * @return 实例
     */
    public static DataAbilityHelper getHelper(Context context) {
        if (helper == null) {
            helper = DataAbilityHelper.creator(context);
        }
        return helper;
    }

    /**
     * 包装文件描述
     *
     * @param parcelFileDescriptor 文件描述
     * @return 流包装
     * @throws IOException
     */
    public static OutputResourceWrapper getOutputResourceWrapper(FileDescriptor parcelFileDescriptor) throws IOException {
        return getOutputResourceWrapper(parcelFileDescriptor, parcelFileDescriptor);
    }

    /**
     * 包装文件描述
     *
     * @param fileDescriptor 文件描述
     * @param parcelFileDescriptor 文件描述
     * @return 流包装
     * @throws IOException
     */
    @NotNull
    public static final OutputResourceWrapper getOutputResourceWrapper(@NotNull FileDescriptor fileDescriptor, @Nullable FileDescriptor parcelFileDescriptor) throws IOException {
        return getOutputResourceWrapper(new FileOutputStream(fileDescriptor), parcelFileDescriptor);
    }

    /**
     * 包装文件流
     *
     * @param fileOutputStream 文件流
     * @return 流包装
     * @throws IOException
     */
    public static final OutputResourceWrapper getOutputResourceWrapper(FileOutputStream fileOutputStream) throws IOException {
        return new OutputResourceWrapper2(fileOutputStream, null);
    }

    /**
     * 包装文件流
     *
     * @param fileOutputStream 文件流
     * @param fileDescriptor 文件描述
     * @return 流包装
     * @throws IOException
     */
    public static final OutputResourceWrapper getOutputResourceWrapper(FileOutputStream fileOutputStream, FileDescriptor fileDescriptor) throws IOException {
        return new OutputResourceWrapper2(fileOutputStream, fileDescriptor);
    }

    /**
     * 包装文件
     *
     * @param filePath 文件路径
     * @param context 上下文
     * @return 流包装
     * @throws IOException
     * @throws DataAbilityRemoteException
     */
    public static OutputResourceWrapper getOutputResourceWrapper(@NotNull String filePath, Context context) throws IOException, DataAbilityRemoteException {
        if (FetchCoreUtils.isUriPath(filePath)) {
            return getOutputResourceWrapper(context, Uri.parse(filePath));
        } else {
            return getOutputResourceWrapper(new File(filePath));
        }
    }

    /**
     * 根据uri包装文件
     *
     * @param context 上下文
     * @param fileUri 文件uri
     * @return 流包装
     * @throws IOException
     * @throws DataAbilityRemoteException
     */
    public static OutputResourceWrapper getOutputResourceWrapper(Context context, Uri fileUri) throws IOException, DataAbilityRemoteException {
        DataAbilityHelper helper = getHelper(context);
        if (Intrinsics.areEqual(fileUri.getScheme(), "content")) {
            String str = String.valueOf(fileUri).replace("content:", "dataability:/");
            FileDescriptor filedesc = helper.openFile(Uri.parse(str), "r");
            if (filedesc == null) {
                throw new FileNotFoundException(fileUri + FetchErrorStrings.FILE_NOT_FOUND);
            }
            return getOutputResourceWrapper(filedesc);
        } else if (Intrinsics.areEqual(fileUri.getScheme(), "file")) {
            File file = new File(fileUri.getDecodedPath());
            if (file.exists() && file.canWrite()) {
                return getOutputResourceWrapper(file);
            } else {
                FileDescriptor parcelFileDescriptor = helper.openFile(fileUri, "w");
                if (parcelFileDescriptor == null) {
                    throw new FileNotFoundException(fileUri + FetchErrorStrings.FILE_NOT_FOUND);
                } else {
                    return getOutputResourceWrapper(parcelFileDescriptor);
                }
            }
        } else {
            throw new FileNotFoundException(fileUri + FetchErrorStrings.FILE_NOT_FOUND);
        }
    }

    /**
     * 根据路径包装文件
     *
     * @param filePath 文件路径
     * @return 流包装
     * @throws IOException
     */
    public static OutputResourceWrapper getOutputResourceWrapper(String filePath) throws IOException {
        File file = new File(filePath);
        if (file.exists()) {
            return getOutputResourceWrapper(file);
        } else {
            throw new FileNotFoundException(file + FetchErrorStrings.FILE_NOT_FOUND);
        }
    }

    /**
     * 包装文件
     *
     * @param file 文件
     * @return 流包装
     * @throws IOException
     */
    public static OutputResourceWrapper getOutputResourceWrapper(File file) throws IOException {
        if (!file.exists()) {
            throw new FileNotFoundException(file.getCanonicalPath() + FetchErrorStrings.FILE_NOT_FOUND);
        }
        return getOutputResourceWrapper(new RandomAccessFile(file, "rw"));
    }

    /**
     * 根据文件流包装文件
     *
     * @param randomAccessFile 文件流
     * @return 流包装
     * @throws IOException
     */
    public static OutputResourceWrapper getOutputResourceWrapper(@NotNull RandomAccessFile randomAccessFile) throws IOException {
        return new OutputResourceWrapper() {
            {
                randomAccessFile.seek(0);
            }

            @Override
            public void write(@NotNull byte[] byteArray, int offSet, int length) throws IOException {
                randomAccessFile.write(byteArray, offSet, length);
            }

            @Override
            public void setWriteOffset(long offset) throws IOException {
                randomAccessFile.seek(offset);
            }

            @Override
            public void flush() throws IOException {
            }

            @Override
            public void close() throws IOException {
                randomAccessFile.close();
            }
        };
    }

    /**
     * 删除文件
     *
     * @param filePath 文件路径
     * @param context 上下文
     * @return 删除结果 boolean
     * @throws DataAbilityRemoteException
     */
    public static boolean deleteFile(String filePath, Context context) throws DataAbilityRemoteException {
        boolean isDelete;
        if (FetchCoreUtils.isUriPath(filePath)) {
            Uri uri = Uri.parse(filePath);
            if (Intrinsics.areEqual(uri.getScheme(), "file")) {
                File file = new File(uri.getDecodedPath());
                isDelete = file.canWrite() && file.exists() ? FetchCoreUtils.deleteFile(file) : false;
            } else if (Intrinsics.areEqual(uri.getScheme(), "content")) {
                String str = String.valueOf(uri).replace("content:", "dataability:/");
                Uri value = Uri.parse(str);
                DataAbilityHelper helper = getHelper(context);
                int count = helper.delete(value, null);
                isDelete = count == 1 ? true : false;
            } else {
                isDelete = false;
            }
        } else {
            isDelete = FetchCoreUtils.deleteFile(new File(filePath));
        }
        return isDelete;
    }

    /**
     * 修改文件名称
     *
     * @param oldFile 旧文件
     * @param newFile 新文件
     * @param context 上下文
     * @return 修改结果 boolean
     * @throws DataAbilityRemoteException
     */
    public static boolean renameFile(String oldFile, String newFile, Context context) throws DataAbilityRemoteException {
        if (FetchCoreUtils.isUriPath(oldFile)) {
            DataAbilityHelper helper = getHelper(context);
            Uri uri = Uri.parse(oldFile);
            if (Intrinsics.areEqual(uri.getScheme(), "file")) {
                File file = new File(uri.getDecodedPath());
                if (file.canWrite() && file.exists()) {
                    return FetchCoreUtils.renameFile(file, new File(newFile));
                } else {
                    Uri oldUri = Uri.parse(oldFile.replace("content:", "dataability:/"));
                    ValuesBucket valuesBucket = new ValuesBucket();
                    valuesBucket.putString(AVStorage.AVBaseColumns.DISPLAY_NAME, newFile);
                    return helper.update(oldUri, valuesBucket, null) > 0;
                }
            } else if (Intrinsics.areEqual(uri.getScheme(), "content")) {
                Uri oldUri = Uri.parse(oldFile.replace("content:", "dataability:/"));
                ValuesBucket valuesBucket = new ValuesBucket();
                valuesBucket.putString(AVStorage.AVBaseColumns.DISPLAY_NAME, newFile);
                return helper.update(oldUri, valuesBucket, null) > 0;
            } else {
                return false;
            }
        } else {
            return FetchCoreUtils.renameFile(new File(oldFile), new File(newFile));
        }
    }

    /**
     * 创建文件
     *
     * @param filePath 文件路径
     * @param increment 增量
     * @param context 上下文
     * @return 文件路径
     * @throws IOException
     * @throws DataAbilityRemoteException
     */
    public static String createFileAtPath(String filePath, boolean increment, Context context) throws IOException, DataAbilityRemoteException {
        if (FetchCoreUtils.isUriPath(filePath)) {
            Uri uri = Uri.parse(filePath);
            if (Intrinsics.areEqual(uri.getScheme(), "file")) {
                return createLocalFile(!TextTool.isNullOrEmpty(uri.getDecodedPath()) ? uri.getDecodedPath() : filePath, increment);
            } else if (Intrinsics.areEqual(uri.getScheme(), "content")) {
                String str = String.valueOf(uri).replace("content:", "dataability:/");
                DataAbilityHelper helper = getHelper(context);
                FileDescriptor parcelFileDescriptor = helper.openFile(Uri.parse(str), "w");
                if (parcelFileDescriptor == null) {
                    throw new IOException(FetchErrorStrings.FNC);
                } else {
                    return filePath;
                }
            } else {
                throw new IOException(FetchErrorStrings.FNC);
            }
        } else {
            return createLocalFile(filePath, increment);
        }
    }

    /**
     * 创建文件
     *
     * @param filePath 文件路径
     * @param increment 增量
     * @return 文件路径
     * @throws IOException
     */
    public static String createLocalFile(String filePath, Boolean increment) throws IOException {
        if (!increment) {
            FetchCoreUtils.createFile(new File(filePath));
            return filePath;
        } else {
            return FetchCoreUtils.getIncrementedFileIfOriginalExists(filePath).getAbsolutePath();
        }
    }

    /**
     * 分配文件
     *
     * @param filePath 文件路径
     * @param contentLength 文件长度
     * @param context 上下文
     * @throws IOException
     * @throws DataAbilityRemoteException
     */
    public static void allocateFile(String filePath, long contentLength, Context context) throws IOException, DataAbilityRemoteException {
        if (FetchCoreUtils.isUriPath(filePath)) {
            Uri uri = Uri.parse(filePath);
            if (Intrinsics.areEqual(uri.getScheme(), "file")) {
                allocateFile(new File(!TextTool.isNullOrEmpty(uri.getDecodedPath()) ? uri.getDecodedPath() : filePath), contentLength);
            } else if (Intrinsics.areEqual(uri.getScheme(), "content")) {
                String str = String.valueOf(uri).replace("content:", "dataability:/");
                DataAbilityHelper helper = getHelper(context);
                FileDescriptor parcelFileDescriptor = helper.openFile(Uri.parse(str), "w");
                if (parcelFileDescriptor == null) {
                    throw new IOException(FetchErrorStrings.FILE_ALLOCATION_ERROR);
                } else {
                    allocateParcelFileDescriptor(parcelFileDescriptor, contentLength);
                }
            } else {
                throw new IOException(FetchErrorStrings.FILE_ALLOCATION_ERROR);
            }
        } else {
            allocateFile(new File(filePath), contentLength);
        }
    }

    /**
     * 分配文件流
     *
     * @param parcelFileDescriptor 文件描述
     * @param contentLength 文件长度
     * @throws IOException
     */
    public static void allocateParcelFileDescriptor(FileDescriptor parcelFileDescriptor, long contentLength) throws IOException {
        if (contentLength > 0) {
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(parcelFileDescriptor);
                if (fileOutputStream.getChannel().size() == contentLength) {
                    return;
                }
                fileOutputStream.getChannel().position(contentLength - 1L);
                fileOutputStream.write(1);
                fileOutputStream.close();
            } catch (Exception e) {
                fileOutputStream.close();
                throw new IOException(FetchErrorStrings.FILE_ALLOCATION_ERROR);
            } finally {
                fileOutputStream.close();
            }
        }
    }

    /**
     * 分配文件
     *
     * @param file 文件
     * @param contentLength 文件长度
     * @throws IOException
     */
    public static void allocateFile(File file, long contentLength) throws IOException {
        if (!file.exists()) {
            FetchCoreUtils.createFile(file);
        }
        if (file.length() == contentLength) {
            return;
        }
        if (contentLength > 0) {
            RandomAccessFile randomAccessFile = null;
            try {
                randomAccessFile = new RandomAccessFile(file, "rw");
                randomAccessFile.setLength(contentLength);
                randomAccessFile.close();
            } catch (Exception e) {
                randomAccessFile.close();
                throw new IOException(FetchErrorStrings.FILE_ALLOCATION_ERROR);
            } finally {
                randomAccessFile.close();
            }
        }
    }

    /**
     * 包装类
     *
     * @since 2021-06-12
     */
    static class OutputResourceWrapper2 extends OutputResourceWrapper {
        private FileOutputStream fileOutputStream;
        private FileDescriptor parcelFileDescriptor;

        public OutputResourceWrapper2(FileOutputStream fileOutputStream, FileDescriptor parcelFileDescriptor) throws IOException {
            this.fileOutputStream = fileOutputStream;
            this.parcelFileDescriptor = parcelFileDescriptor;
            fileOutputStream.getChannel().position(0);
        }

        @Override
        public void write(@NotNull byte[] byteArray, int offSet, int length) throws IOException {
            this.fileOutputStream.write(byteArray, offSet, length);
        }

        @Override
        public void setWriteOffset(long offset) throws IOException {
            this.fileOutputStream.getChannel().position(offset);
        }

        @Override
        public void flush() throws IOException {
            this.fileOutputStream.flush();
        }

        @Override
        public void close() throws IOException {
            this.fileOutputStream.close();
        }
    }
}
